/**
 * 验证模块
 */

// 导入验证库
import { body, query, param } from "express-validator";
import { isString } from "./utils.js";

/**
 * 将需要验证的值转换为数组类型
 *
 * @param {string | string[]} val 需要被转换的值
 * @returns {string[]}
 */
function toArray(val) {
  if (Array.isArray(val)) return val;
  if (isString(val) && val.length > 0) return val.split(",");
  return [];
}

// 定义验证器
const validators = {
  email: body("email").trim().isEmail().withMessage("不是有效的邮箱地址"),
  password: body("password")
    .trim()
    .isLength({ min: 6, max: 20 })
    .withMessage("密码长度必须在 6 到 20 个字符之间"),
  confirmPassword: body("confirmPassword")
    .trim()
    .custom((val, { req }) => val == req.body.password)
    .withMessage("两次密码不一致"),
  nickname: body("nickname")
    .trim()
    .isLength({ min: 1, max: 25 })
    .withMessage("昵称长度必须在 1 到 25 个字符之间"),
  code: body("code")
    .trim()
    .isLength({ min: 4, max: 4 })
    .withMessage("验证码长度必须是 4 个字符"),
  title: body("title")
    .trim()
    .isLength({ min: 3, max: 150 })
    .withMessage("标题长度必须在 3 到 150 个字符之间"),
  start_date: body("start_date")
    .optional()
    .trim()
    .isDate()
    .withMessage("start_date 不符合参数要求"),
  end_date: body("end_date")
    .optional()
    .trim()
    .isDate()
    .withMessage("end_date 不符合参数要求"),
  cover: body("cover")
    .custom((val) => {
      return /^(https?:\/\/(([a-zA-Z0-9]+-?)+[a-zA-Z0-9]+\.)+[a-zA-Z]+)(:\d+)?(\/.*)?(\?.*)?(#.*)?$/.test(
        val
      );
    })
    .withMessage("请输入正确的url地址"),
  digest: body("digest")
    .optional()
    .trim()
    .isLength({ min: 3, max: 255 })
    .withMessage("摘要长度必须在 3 到 255 个字符之间"),
  published: body("published")
    .trim()
    .isIn([0, 1, true, false, "true", "false"])
    .withMessage("published 不符合参数要求")
    .toBoolean(),
  tags: body("tags")
    .optional()
    .customSanitizer((val) => {
      if (Array.isArray(val)) return val;
      if (!val) return [];
      if (isString(val)) return val.split(",");
      return [];
    }),
  category: body("category")
    .optional()
    .trim()
    .isIn(["latest", "hits"])
    .withMessage("category 必须是 latest 或 hits"),
  postId: body("postId").trim().isInt().withMessage("postId 必须是整数"),
  description: body("description")
    .optional()
    .trim()
    .isLength({ min: 3, max: 255 })
    .withMessage("描述长度必须在 3 到 255 个字符之间"),
  name: body("name")
    .trim()
    .isLength({ min: 2, max: 30 })
    .withMessage("名称长度必须在 2 到 30 个字符之间"),
  job: body("job")
    .optional()
    .trim()
    .isLength({ min: 2, max: 50 })
    .withMessage("职位长度必须在 2 到 50 个字符之间"),
  basic: body("basic")
    .optional()
    .trim()
    .isLength({ min: 2 })
    .withMessage("基本信息至少 2 个字符"),
  contact: body("contact")
    .optional()
    .trim()
    .isLength({ min: 2 })
    .withMessage("联系方式至少 2 个字符"),
  education: body("education")
    .optional()
    .trim()
    .isLength({ min: 2 })
    .withMessage("教育背景至少 2 个字符"),
  skills: body("skills")
    .optional()
    .trim()
    .isLength({ min: 2 })
    .withMessage("技能长度至少 2 个字符"),
  workExperience: body("workExperience")
    .optional()
    .trim()
    .isLength({ min: 2 })
    .withMessage("工作经历至少 2 个字符"),

  query: {
    title: query("title").optional().trim(),
    start_date: query("start_date")
      .optional({ values: "falsy" })
      .isDate("YYYY-MM-DD")
      .withMessage("错误的日期格式"),
    end_date: query("end_date")
      .optional({ values: "falsy" })
      .isDate("YYYY-MM-DD")
      .withMessage("错误的日期格式"),
    tags: query("tags")
      .optional()
      .customSanitizer((val) => {
        return toArray(val);
      }),
    orderby: (fields) => {
      const filterSymbol = (val) => (val.startsWith("-") ? val.slice(1) : val);
      return query("orderby")
        .optional()
        .custom((val) => {
          const vs = toArray(val);
          return vs.every((i) => fields.includes(filterSymbol(i)));
        })
        .withMessage("不是有效的排序字段");
    },
    limit: query("limit")
      .optional()
      .toInt()
      .isInt()
      .withMessage("limit 必须是整数"),
    offset: query("offset")
      .optional()
      .toInt()
      .isInt()
      .withMessage("offset 必须是整数"),
  },
  params: {
    id: param("id").isInt().withMessage("id 必须是整数"),
  },
};

export default validators;
